#pragma once

extern MysqlConnection emptyMysqlConnection;
#define SQL_ESCAPE_STRING(s) (emptyMysqlConnection.EscapeString(s))

template <typename T>
std::string CreateSQL4InsertEntity(const T &entity)
{
	std::ostringstream s;
	s << "INSERT INTO `" << GetTableName<T>() << "` VALUES(";
	for (size_t i = 0, n = GetTableFieldNumber<T>(); i < n; ++i) {
		auto value = GetTableFieldValue(entity, i);
		s << "'" << SQL_ESCAPE_STRING(value) << "',";
	}
	s.seekp(-1, std::ios::cur) << ")";
	return s.str();
}

template <typename T>
std::string CreateSQL4SelectEntity(const char* where = NULL)
{
	std::ostringstream s;
	s << "SELECT ";
	for (size_t i = 0, n = GetTableFieldNumber<T>(); i < n; ++i) {
		auto name = GetTableFieldNameByIndex<T>(i);
		s << "`" << name << "`,";
	}
	s.seekp(-1, std::ios::cur) << " FROM `" << GetTableName<T>() << "`";
	if (where != NULL) {
		s << " WHERE " << where;
	}
	return s.str();
}

template <typename T>
std::string CreateSQL4UpdateEntity(const T &entity, const char* where = NULL,
	const std::vector<ssize_t>& ingores = {})
{
	std::ostringstream s;
	s << "UPDATE `" << GetTableName<T>() << "` SET ";
	for (size_t i = 0, n = GetTableFieldNumber<T>(); i < n; ++i) {
		if (IS_VECTOR_CONTAIN_VALUE(ingores, i)) { continue; }
		auto name = GetTableFieldNameByIndex<T>(i);
		auto value = GetTableFieldValue(entity, i);
		s << "`" << name << "`='" << SQL_ESCAPE_STRING(value) << "',";
	}
	s.seekp(-1, std::ios::cur) << " ";
	if (where != NULL) {
		s << "WHERE " << where;
	}
	return s.str();
}

template <typename T>
std::string CreateSQL4DeleteEntity(const char* where = NULL)
{
	std::ostringstream s;
	s << "DELETE FROM `" << GetTableName<T>() << "`";
	if (where != NULL) {
		s << " WHERE " << where;
	}
	return s.str();
}

template <typename T>
std::string CreateSQL4InsertEntityValues(const T &entity)
{
	std::ostringstream s;
	s << ",(";
	for (size_t i = 0, n = GetTableFieldNumber<T>(); i < n; ++i) {
		auto value = GetTableFieldValue(entity, i);
		s << "'" << SQL_ESCAPE_STRING(value) << "',";
	}
	s.seekp(-1, std::ios::cur) << ")";
	return s.str();
}

template <typename T>
std::string CreateSQL4InsertOrUpdateEntity(const T &entity,
	const std::vector<ssize_t>& ingores = {})
{
	std::ostringstream s;
	s << "INSERT INTO `" << GetTableName<T>() << "` VALUES(";
	for (size_t i = 0, n = GetTableFieldNumber<T>(); i < n; ++i) {
		auto value = GetTableFieldValue(entity, i);
		s << "'" << SQL_ESCAPE_STRING(value) << "',";
	}
	s.seekp(-1, std::ios::cur) << ") ON DUPLICATE KEY UPDATE ";
	for (size_t i = 0, n = GetTableFieldNumber<T>(); i < n; ++i) {
		if (IS_VECTOR_CONTAIN_VALUE(ingores, i)) { continue; }
		auto name = GetTableFieldNameByIndex<T>(i);
		auto value = GetTableFieldValue(entity, i);
		s << "`" << name << "`='" << SQL_ESCAPE_STRING(value) << "',";
	}
	s.seekp(-1, std::ios::cur) << " ";
	return s.str();
}

template <typename T>
T LoadEntityFromMysqlRow(MysqlRow row)
{
	T entity;
	for (size_t i = 0, n = GetTableFieldNumber<T>(); i < n; ++i, row.Next()) {
		SetTableFieldValue(entity, i, {row.GetString(), row.GetLength()});
	}
	return entity;
}

template <typename T>
std::string LoadSQLXListFromINetStream(INetStream& stream)
{
	std::ostringstream s;
	while (!stream.IsReadableEmpty()) {
		s << stream.Read<T>() << ',';
	}
	auto str = s.str();
	if (!str.empty()) {
		str.pop_back();
	}
	return str;
}

template <typename T>
std::vector<ssize_t> ConvertEntityFieldIndexs(
	std::initializer_list<const char*>&& names) {
	std::vector<ssize_t> indexs;
	indexs.reserve(names.size());
	for (auto name : names) {
		indexs.push_back(GetTableFieldIndexByName<T>(name));
	}
	return indexs;
}
